
#pragma once

namespace threading
{

	class job_queue_type;

	class job_notify_type {

		enum notifies {
			postmessage,
			setevent,
			none
		} notification;

		MSG msg;

		void notify(); // this gets called by 

	public:

		bool repost, shouldDelete;

		job_notify_type();
		job_notify_type(const job_notify_type& _src);
		void setSignal( HANDLE signal );
		void setPostMsg( HWND _hwnd, UINT _message, WPARAM _wParam, LPARAM _lParam );
		~job_notify_type();
		void operator = (const job_notify_type& _src);
		friend class job_queue_type;

	};

	class job_type {

	protected:

		OVERLAPPED ovp; // this MUST be the first element in this structure

	private:

		job_type *next;

	public:

		job_type( );
		virtual ~job_type();
		virtual job_notify_type execute( job_queue_type *_callingQueue, DWORD _bytesTransferred, BOOL _success );
		friend class job_queue_type;
	};

	class finishjob_type : public job_type {

	protected:

		OVERLAPPED ovp; // this MUST be the first element in this structure

	private:

		job_type *next;

	public:

		HANDLE handle;

		finishjob_type( );
		virtual ~finishjob_type();
		virtual job_notify_type execute( job_queue_type *_callingQueue, DWORD _bytesTransferred, BOOL _success );
		friend class job_queue_type;
	};

	// simple wrapper for interlocked increment

	class lockable_type {
		CRITICAL_SECTION section;
		int lock_count;

	public:

		lockable_type( const lockable_type& _src ); // evil if _src locked
		lockable_type operator = ( const lockable_type& _src ); // evil if _src locked
		lockable_type( int _spin_count );
		lockable_type();
		virtual ~lockable_type();

		void initialize();

		void lock();
		void unlock();
		bool locked();

	};

	class locker_type {
		lockable_type *lockable;

	public:

		locker_type( lockable_type *_lockable );
		virtual ~locker_type();

	};

	const int maxWorkerThreads = 64;  // and that number is way high

	class job_queue_type : public lockable_type {

		job_type *base, *last;

		HANDLE ioCompPort;

		unsigned int threadIds[ maxWorkerThreads ];
		HANDLE threads[ maxWorkerThreads ];

		int numWorkerThreads;

		job_type shutDownJob;

		bool shutDownOrdered;

		int num_outstanding_jobs;
		HANDLE empty_queue_event;

	public:

		inline HANDLE getPort() { return ioCompPort; }
		inline DWORD getThreadCount() { return numWorkerThreads; }
		inline bool wasShutDownOrdered() { return shutDownOrdered; }

		job_queue_type();
		virtual ~job_queue_type();

		void start( int _numThreads );
		void postJobMessage( job_type *_jobMessage );
		void shutDown();
		void kill();
		static unsigned int __stdcall jobQueueThread( void *_arg );

		void waitForThreadFinished();
		void waitForEmptyQueue();

		int numberOfProcessors();

	};

}
